package hotel.quartz.oversea.job.callback;

import com.alibaba.fastjson.JSON;
import hotel.base.oversea.constant.CallbackConstants;
import hotel.base.oversea.constant.CommonConstants;
import hotel.base.oversea.constant.CommonUrlConstants;
import hotel.base.oversea.constant.MeituanConstants;
import hotel.base.oversea.constant.enums.MessageEnums;
import hotel.base.oversea.constant.quartz.UrlSwitchsEnums;
import hotel.base.oversea.dto.switchs.SwitchCreateRoomDto;
import hotel.base.oversea.utils.*;
import hotel.quartz.oversea.config.service.RedisService;
import hotel.quartz.oversea.job.base.BaseJob;
import hotel.quartz.oversea.util.JobRestTemplateUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
public class MtCbGoodsPriceRedisRemoveJob implements BaseJob {
    private String timestamp = "Mhj"+String.valueOf(System.currentTimeMillis());

    @Autowired
    RedisService redisService;

    @Autowired
    RestTemplate restTemplate;

    public Integer getDaysCommonBaseSet() {//返回3天
        Integer returnDays;
        String daysCom = (String)redisService.get(CallbackConstants.SWMT_PRICE_STATUS_DAYS);
        if(ObjectUtils.isEmpty(daysCom)){
            Result result = RestTemplateUtils.get(CommonUrlConstants.ADMIN_HOST+"/sysCommonBase/value/"+ CallbackConstants.SWMT_PRICE_STATUS_DAYS,null,restTemplate);
            if(result.getCode() == CommonConstants.SUCCESS && !ObjectUtils.isEmpty(result.getData())){
                daysCom = (String)result.getData();
                redisService.set(CallbackConstants.SWMT_PRICE_STATUS_DAYS,daysCom);
                returnDays = Integer.valueOf(daysCom);
            }else{
                SendUtils.dingMsgNotLog("获取基础配置days异常请排查", DateUtil.getCurrTime()+" 当前设置默认值价格房态查询3天 result="+ GsonUtils.GsonString(result), MessageEnums.genre.GOODS_STATUS_AND_PRICE.getCode(),restTemplate);
                returnDays = 3;//有异常默认3天并推送钉钉
            }
        }else{
            returnDays = Integer.valueOf(daysCom);
        }
        String isSubOneDays = (String)redisService.get("MtCbGoodsPriceRedisRemoveJob_sub_one_days");
        if(!ObjectUtils.isEmpty(isSubOneDays)){//凌晨全量减一天，夜间对于新载入的一天不做删除缓存操作
            String thisHourStr = DateUtil.formatDate(new Date(),"HH");
            if("02,03,04,05,06".contains(String.valueOf(thisHourStr))){
                return  returnDays-1;
            }
        }
        return  returnDays;
    }

    /**
     *  定时器逐量 删除 美团callback产品价格缓存，间隔sleep删除（控制推送的量，携程消费不过来）
     * @param jobExecutionContext
     */
    @Override
    @SneakyThrows
    public void execute(JobExecutionContext jobExecutionContext) {
        /***
         * @Author: lmf
         * @Date: 2021/4/12
         * 每个月月初降低价格公式
         * 控制是否开启降价的 2021-04-12
         */
        String key="switch_finish_order_num";
        if(!redisService.exists(key)){
            int day= Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
            int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
            //每个月1号降低价格  1-5号
            if(day==1){
                //标记公式是否改过
                if(redisService.exists("switch_close_price_formula_adjust")){
                    redisService.remove("switch_close_price_formula_adjust");
                }
                if(hour==3){//凌晨三店全量需要调整价格
                    log.info("===========1号开始调整价格公式=============");
                    String switchHost = CommonUrlConstants.SWITCHS_ONLINE_HOST;
                    String getUpMtHotel = switchHost+ UrlSwitchsEnums.SwitchCheckHotelRoomIsCreateJob.SWITCH_ADJUST_HOTEL_PRICE_FORMULA.getValue();
                    //发起请求
                    Map<Object,Object> params = new HashMap();
                    params.put("timestamp",timestamp);
                    params.put("genre",0);
                    Result response = JobRestTemplateUtils.post(getUpMtHotel, JSON.toJSONString(params),restTemplate);
                    log.info("=======号开始调整价格公式请求的返回值为{}=====",response);
                }
            }else if(day<=5){//统计携程订单量 一线 2 二线 1
                if(!redisService.exists("switch_close_price_formula_adjust")){
                    log.info("=====判断是否满足美团订单条件，如果满足就把价格公式调整回来=======");
                    key="switch_one_switch_order_num_rate";
                    int num=2000;
                    if(redisService.exists(key)){
                        num= (int) redisService.get(key);
                    }
                    String switchHost = CommonUrlConstants.SWITCHS_ONLINE_HOST;
                    String getUpMtHotel = switchHost+ UrlSwitchsEnums.SwitchCheckHotelRoomIsCreateJob.SWITCH_STATATIS_HOTEL_ORDER_NUM.getValue();
                    //发起请求
                    Map<Object,Object> params = new HashMap();
                    params.put("timestamp",timestamp);
                    params.put("genre",0);
                    Result response = JobRestTemplateUtils.post(getUpMtHotel, JSON.toJSONString(params),restTemplate);
                    log.info("=======请求订单数据量请求的返回值为{}=====",response);
                    int orderNum= new Double(String.valueOf(response.getData())).intValue();
                    if(orderNum>=num){//如果达标了，佣金提高了,价格公式调整回来
                        log.info("=====满足美团订单条件，把价格公式调整回来=======");
                        //发起请求
                        getUpMtHotel = switchHost+ UrlSwitchsEnums.SwitchCheckHotelRoomIsCreateJob.SWITCH_ADJUST_HOTEL_PRICE_FORMULA.getValue();
                        params.put("genre",1);
                        response = JobRestTemplateUtils.post(getUpMtHotel, JSON.toJSONString(params),restTemplate);
                        log.info("=======满足美团订单条件，把价格公式调整回来,请求的返回值为{}=====",response);
                        if(response.getCode()== CommonConstants.SUCCESS){
                            redisService.set("switch_close_price_formula_adjust",1);
                        }
                    }
                }

            }
        }
        log.info("Mt Cb Goods Price Redis Remove Job {} >>>>>>>> 美团callback产品缓存删除定时器执行时间: {}",timestamp, DateUtil.getCurrTime());
        //每次执行之前，请求携程接口,清除缓存价格公式
        requestSwitchInterface();
        //从缓存中获取上架的酒店产品
        Long allNeedRemoveGoods = redisService.queueSize(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE);
        Integer daysForJob = getDaysCommonBaseSet();//不载入新的一天

        if(allNeedRemoveGoods==0){
            Map<String,String> redisError = new HashMap<>();
            if(null != redisService.get("MtCbGoodsPriceRedisRemoveJob_error")){//人工set缓存进行指定产品删除价格缓存
                redisError = GsonUtils.GsonToMaps((String)redisService.get("MtCbGoodsPriceRedisRemoveJob_error"));
            }
            if(null != redisError && redisError.size()>0){
                log.info("MtCbGoodsPriceRedisRemoveJob_error不为空，人工set缓存进行指定产品删除价格缓存");
                for (Map.Entry m:redisError.entrySet()){
                    redisService.lPush(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE, m.getKey());
                }
            }else{
                log.info("Mt Cb Goods Price Redis Remove Job  {} allNeedRemoveGoods  当前队列size=0，获取缓存上架酒店产品，首轮跑批",timestamp, DateUtil.getCurrTime());
                //重置该表示待查询的酒店ids,,opsForList() 每拿出一个hotelID就会集合中剔除一个
                List<SwitchCreateRoomDto> swUpHotelIdGodosData = findUpHotelGoodsData();
                if(null != swUpHotelIdGodosData && swUpHotelIdGodosData.size()>0){
                    //构建数据
                    for (SwitchCreateRoomDto dto:swUpHotelIdGodosData){
                        if(!ObjectUtils.isEmpty(dto.getMtHotelId()) && !ObjectUtils.isEmpty(dto.getMtGoodId())){
                            String mtHotelId = String.valueOf(dto.getMtHotelId());
                            String goodsId = String.valueOf(dto.getMtGoodId());
                            redisService.lPush(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE, mtHotelId+"_"+goodsId);
                        }
                    }
                }else{
                    log.error("Mt Cb Goods Price Redis Remove Job {} 全量价格价格定时器,未查询到上架酒店产品信息",timestamp);
                }
            }
        }
        allNeedRemoveGoods = redisService.queueSize(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE);
        log.info("Mt Cb Goods Price Redis Remove Job 查询到产品数量为allNeedRemoveGoods={}",allNeedRemoveGoods);
        if(allNeedRemoveGoods>0){
            String removeStart = CallbackConstants.REMOVE_GOODS_DATE_INFO_START;
            Date startDateBefore = DateUtil.addSecond(new Date(),new BigDecimal(30).multiply(new BigDecimal(60)).intValue());
            String startDate = DateUtil.formatDate(startDateBefore,"yyyy-MM-dd HH:mm:ss");
            redisService.setUnit(removeStart,startDate,12L,TimeUnit.HOURS);

            String nowDate = DateUtil.formatDate(new Date(),"yyyy-MM-dd");
            Integer sleepTime = 20;//20毫秒删除一个日期产品  产品数量要x3天  一个产品=20*3=60毫秒
            Map<String,String> error = new HashMap<>();
            if(null != redisService.get("MtCbGoodsPriceRedisRemoveJob_sleepTime")){
                sleepTime = (Integer) redisService.get("MtCbGoodsPriceRedisRemoveJob_sleepTime");
            }
            String finTime = "120";
            log.info("Mt Cb Goods Price Redis Remove Job 计算时间allNeedRemoveGoods={}，sleepTime={},daysForJob={}",allNeedRemoveGoods,sleepTime,daysForJob);
            try {
                finTime = BigDecimal.valueOf(allNeedRemoveGoods).multiply(BigDecimal.valueOf(sleepTime*(daysForJob))).divide(new BigDecimal(1000*60)).toString();
            }catch (Exception e){
                e.printStackTrace();
            }

            SendUtils.dingMsgNotLog("[REMOVE-PRICE]每日全量价格，即将执行 ", DateUtil.getCurrTime() +" 共需处理="+allNeedRemoveGoods+"，预计完成时间= "+finTime+" 分钟", MessageEnums.genre.GOODS_STATUS_AND_PRICE.getCode(),restTemplate);
            //根据预计时间，先设置删除缓存可能结束时间
            String removeEnd = CallbackConstants.REMOVE_GOODS_DATE_INFO_END;
            Date endDate = DateUtil.addSecond(new Date(),new BigDecimal(finTime).add(new BigDecimal(30)).multiply(new BigDecimal(60)).intValue());
            redisService.setUnit(removeEnd, DateUtil.formatDate(endDate,"yyyy-MM-dd HH:mm:ss"),12L,TimeUnit.HOURS);
            log.info("删除缓存定时器11 startDate={}，endDate={},finTime={}",startDate,endDate,finTime);
            try {
                Thread.sleep(5000);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }

            log.info("执行参数：nowDate={},sleepTime={},finTime={},allNeedRemoveGoods={}",nowDate,sleepTime,finTime,allNeedRemoveGoods);

            Integer dealNum = 0;
            for (int i = 0; i < allNeedRemoveGoods; i++) {
                if(null != redisService.get("MtCbGoodsPriceRedisRemoveJob_close_todo")){
                    log.info("程序判断主动停止");
                    break;
                }
                String hotelIdAndGoodsId = (String)redisService.RPop(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE);
                log.info("pop队列，i={},hotelIdAndGoodsId={}",i,hotelIdAndGoodsId);
                if(ObjectUtils.isEmpty(hotelIdAndGoodsId)){
                    log.info("全量价格删除美团产品价格缓存，队列已无数据，hotelIdAndGoodsId为空");
                    break;
                }else{
                    Map<String,Object> returnMap = removeOneGoodsDays(0,nowDate,sleepTime,hotelIdAndGoodsId,daysForJob,"1",error,dealNum);
                    dealNum = (Integer) returnMap.get("dealNum");
                    error = (Map<String,String>) returnMap.get("error");
                }

            }
            if(null != redisService.get("MtCbGoodsPriceRedisRemoveJob_close_todo")){
                return;
            }
            log.info("第一次处理结束：循环处理了dealNum={},共需处理allNeedRemoveGoods={}",dealNum,allNeedRemoveGoods);
            Map<String,String> errorAgain = new HashMap<>();
            if(null != error && error.size()>0){
                for (Map.Entry err:error.entrySet()){
                    String hotelIdAndGoodsId = String.valueOf(err.getKey());
                    redisService.lPush(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE, hotelIdAndGoodsId);
                }
                Long againSize = redisService.queueSize(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE);
                log.info("删除失败的酒店产品再次push到队列中,队列size={}",redisService.queueSize(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE));

                log.info("Mt Cb Goods Price Redis Remove Job 第一次存在删除缓存失败size={},error={}",error.size(),error);
                if(null == redisService.get("MtCbGoodsPriceRedisRemoveJob_push_close")){//失败的再次操作remove
                    log.info("Mt Cb Goods Price Redis Remove Job 删除缓存失败 当前进入第二次处理，跑一遍删除失败的产品",error);
                    for (int i = 0; i < againSize; i++) {
                        if(null != redisService.get("MtCbGoodsPriceRedisRemoveJob_close_todo")){
                            log.info("第二次，程序判断主动停止");
                            break;
                        }
                        String hotelIdAndGoodsId = (String)redisService.RPop(MeituanConstants.REIDS_MT_GOODS_PRICE_DAY_REMOVE);
                        log.info("第二次，pop队列，i={},hotelIdAndGoodsId={}",i,hotelIdAndGoodsId);
                        if(!ObjectUtils.isEmpty(hotelIdAndGoodsId)){
                            Map<String,Object> returnMap = removeOneGoodsDays(0,nowDate,sleepTime,hotelIdAndGoodsId,daysForJob,"2",errorAgain,dealNum);
                            dealNum = (Integer) returnMap.get("dealNum");
                            errorAgain = (Map<String,String>) returnMap.get("error");
                        }else{
                            log.info("第二次，删除美团产品价格缓存，队列已无数据，hotelIdAndGoodsId为空");
                            break;
                        }
                    }
                    if(!ObjectUtils.isEmpty(errorAgain)){
                        log.error("第二次存在删除缓存失败产品价格日期：errorAgain={}，size={}", GsonUtils.GsonString(errorAgain),errorAgain.size());
                    }
                }
                log.info("第二次处理结束：循环处理了dealNum={},共需处理allNeedRemoveGoods={}",dealNum,allNeedRemoveGoods);
            }
            Date endDate2Before = DateUtil.addSecond(new Date(),new BigDecimal(30).multiply(new BigDecimal(60)).intValue());
            String endDate2 = DateUtil.formatDate(endDate2Before,"yyyy-MM-dd HH:mm:ss");
            redisService.setUnit(removeEnd,endDate2,12L,TimeUnit.HOURS);
            log.info("删除缓存定时器22 startDate={}，endDate2={}",startDate,endDate2);
            if(new BigDecimal(allNeedRemoveGoods).compareTo(new BigDecimal(dealNum))!=0){
                SendUtils.dingMsgNotLog("[REMOVE-PRICE]每日全量价格，删除成功价格缓存数量不符 ", DateUtil.getCurrTime() +" 共需处理="+allNeedRemoveGoods+"，完成数量="+dealNum+" 失败处理："+ GsonUtils.GsonString(errorAgain), MessageEnums.genre.GOODS_STATUS_AND_PRICE.getCode(),restTemplate);
            }else{
                SendUtils.dingMsgNotLog("[REMOVE-PRICE-SUCCESS]每日全量价格，完成删除价格缓存 ", DateUtil.getCurrTime() +" 共需处理="+allNeedRemoveGoods+"，完成数量="+dealNum, MessageEnums.genre.GOODS_STATUS_AND_PRICE.getCode(),restTemplate);
            }

        }

        log.info("Mt Cb Goods Price Redis Remove Job {} >>>>>>>> 美团callback产品缓存删除定时器结束时间: {},{}",timestamp, DateUtil.getCurrTime());
    }

    public Map<String,Object> removeOneGoodsDays(Integer count,String nowDate,Integer sleepTime,String hotelIdAndGoodsId,Integer daysForJob,String index,Map<String,String> error,Integer dealNum){
        Map<String,Object> returnMap = new HashMap<>();
        Integer max = 1000;//暂定1000
        if(null != redisService.get("MtCbGoodsPriceRedisRemoveJob_sw_max")){
            max = (Integer) redisService.get("MtCbGoodsPriceRedisRemoveJob_sw_max");
        }
        Long swCount = redisService.queueSize(MeituanConstants.REDIS_CHANGE_GOODS_DATA_MANY_HOTEL);
        if(new BigDecimal(count).compareTo(new BigDecimal(100))<0 && new BigDecimal(swCount).compareTo(new BigDecimal(max))>0){
            Integer countSleep = 2000;
            log.info("删除缓存前判断携程队列已超出max={},当前进入sleep={},count={}，swCount={}",max,countSleep,count,swCount);
            count +=1;
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            //判断 携程 堆积  。。。。。。。。
            return removeOneGoodsDays(count,nowDate,sleepTime,hotelIdAndGoodsId,daysForJob,index,error,dealNum);
        }else{
            String redisDate = nowDate;
            Boolean thisGoodsExsiError = false;
            for (int i = 0; i <daysForJob; i++) {
                try {
                    Thread.sleep(sleepTime);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }

                Boolean rm = redisService.rm(CallbackConstants.REDIS_KEY_CALLBACK_CHANGE_PRICE_HEAD+hotelIdAndGoodsId+"_"+redisDate);
                if(!rm){
                    thisGoodsExsiError = true;
                    log.info("index={}该产品该日期删除缓存失败：{}",index, CallbackConstants.REDIS_KEY_CALLBACK_CHANGE_PRICE_HEAD+hotelIdAndGoodsId+"_"+redisDate);
                    error.put(hotelIdAndGoodsId,index);
                    break;
                }

                if(i != daysForJob-1){
                    redisDate = DateUtil.formatDate(DateUtil.addDay(redisDate,1L),"yyyy-MM-dd");//下一天
                }
            }
            if(!thisGoodsExsiError){
                dealNum+=1;
            }
        }
        returnMap.put("dealNum",dealNum);
        returnMap.put("error",error);
        return returnMap;
    }

    private List<SwitchCreateRoomDto> findUpHotelGoodsData() {
        //获取上架的酒店+产品信息
        Result result = JobRestTemplateUtils.post(CommonUrlConstants.SWITCHS_ONLINE_HOST+"/switchHotelUp/getUpHotelGoodsDataForRemove",null,restTemplate);
        List<SwitchCreateRoomDto> upList = GsonUtils.jsonToList(result.getData().toString(), SwitchCreateRoomDto.class);
        if(null != upList){
            log.info("Mt Cb Goods Price Redis Remove Job findUpHotelGoodsData获取到上架酒店产品数量size={}",upList.size());
        }else{
            log.error("Mt Cb Goods Price Redis Remove Job 异常  findUpHotelGoodsData获取到上架酒店产品数量size={}",upList.size());
        }
        return upList;
    }
    /***
     * @Author: lmf
     * @Date: 2021/3/8
     * 请求携程接口，清除缓存旧价格公式
     */
    private void requestSwitchInterface() {
        String url= CommonUrlConstants.SWITCHS_ONLINE_HOST+ UrlSwitchsEnums.SwitchCheckHotelRoomIsCreateJob.SWITCH_REMOVE_HOTEL_PRICE_CACHE.getValue();
        Result result = JobRestTemplateUtils.post(url,null,restTemplate);
        if(result.getCode()!= CommonConstants.SUCCESS){
            log.info("======请求携程接口，清除缓存旧价格公式出现异常=========");
        }
    }



}
